package org.pine.dictionary.service.manager;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.pine.dictionary.bean.PageRequest;
import org.pine.dictionary.dao.entity.SuperEntity;
import org.pine.dictionary.service.query.BaseQuery;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 * 基础管理类
 * </p>
 *
 * @author pine
 * @since 2024-05-16
 */
public abstract class BaseManager<Entity extends SuperEntity<?>, EntityBo, Mapper extends BaseMapper<Entity>, Query extends BaseQuery, PrimaryKey extends Serializable, ID extends Serializable> {

    @Autowired
    protected Mapper mapper;

    @Autowired
    protected SqlSessionFactory sqlSessionFactory;

    protected final Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseManager.class);

    protected Class<Entity> entityClass = this.currentModelClass();

    protected Class<EntityBo> entityBoClass = this.currentModelBoClass();

    protected Class<Mapper> mapperClass = this.currentMapperClass();

    protected static final String ASC = "asc";
    protected static final String DESC = "desc";

    protected static final String DEFAULT_ORDER_BY_FIELD = "id";

    public BaseManager() {
    }

    @SuppressWarnings("unchecked")
    protected Class<Entity> currentModelClass() {
        return (Class<Entity>) this.typeArguments[0];
    }

    @SuppressWarnings("unchecked")
    protected Class<EntityBo> currentModelBoClass() {
        return (Class<EntityBo>) this.typeArguments[1];
    }

    @SuppressWarnings("unchecked")
    protected Class<Mapper> currentMapperClass() {
        return (Class<Mapper>) this.typeArguments[2];
    }

    public void save(Entity entity) {
        this.mapper.insert(entity);
    }

    public int saveBatch(List<? extends Entity> entityList) {
        int insertNum = 0;
        if (CollUtil.isNotEmpty(entityList)) {
            try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
                Mapper mapper = sqlSession.getMapper(mapperClass);
                for (Entity entity : entityList) {
                    insertNum += mapper.insert(entity);
                }
                sqlSession.commit();
            }
        }
        return insertNum;
    }

    public void updateById(Entity entity) {
        this.mapper.updateById(entity);
    }


    /**
     * 查询单条数据
     *
     * @param businessId 业务ID
     * @return 业务对象
     */
    public abstract EntityBo getOne(ID businessId);

    /**
     * 查询单条数据
     *
     * @param query 查询参数
     * @return 业务对象
     */
    public abstract EntityBo getOne(Query query);

    /**
     * 分页查询实现
     *
     * @param request 请求参数
     * @return 响应结果
     */
    public IPage<EntityBo> page(PageRequest<Query> request) {
        // 组装查询条件
        LambdaQueryWrapper<Entity> queryWrapper = encapsulateQueryWrapper(request.getData());

        // 分页查数据
        Page<Entity> entityPage = this.mapper.selectPage(new Page<>(request.getPageNum(), request.getPageSize()), queryWrapper);

        // 根据查询结果组装业务对象列表
        List<EntityBo> entityBos = createBo(entityPage.getRecords());

        // 返回业务分页结果
        return Page.<EntityBo>of(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal(), entityPage.searchCount()).setRecords(entityBos);
    }

    /**
     * 封装查询条件
     *
     * @param request 请求参数
     * @return 查询条件wrapper
     */
    protected LambdaQueryWrapper<Entity> encapsulateQueryWrapper(Query request) {
        QueryWrapper<Entity> wrapper = new QueryWrapper<>();
        if (Objects.isNull(request)) {
            return wrapper.lambda();
        }

        // 处理查询字段
        String[] underLineFields = request.convertToUnderLineFields();
        if (Objects.nonNull(underLineFields) && underLineFields.length > 0) {
            wrapper.select(underLineFields);
        }


        // 处理排序规则
        String orderBy = request.getOrderBy();
        if (StrUtil.isNotBlank(orderBy)) {
            String[] orderByExpressions = orderBy.split(StrUtil.COMMA);
            List<String> ascFields = new ArrayList<>();
            List<String> descFields = new ArrayList<>();
            for (String orderByExpression : orderByExpressions) {
                if (orderByExpression.endsWith(ASC)) {
                    ascFields.add(orderByExpression.replace(StrUtil.DASHED + ASC, StrUtil.EMPTY));
                    continue;
                }
                if (orderByExpression.endsWith(DESC)) {
                    descFields.add(orderByExpression.replace(StrUtil.DASHED + DESC, StrUtil.EMPTY));
                }
            }

            // 没有排序规则，使用ID倒序排序
            if (CollUtil.isEmpty(descFields) && CollUtil.isEmpty(ascFields)) {
                wrapper.orderByDesc(DEFAULT_ORDER_BY_FIELD);
                return wrapper.lambda();
            }
            if (CollUtil.isNotEmpty(ascFields)) {
                wrapper.orderByAsc(ascFields);
            }
            if (CollUtil.isNotEmpty(descFields)) {
                wrapper.orderByDesc(descFields);
            }
        } else {
            // 没有排序规则，使用ID倒序排序
            wrapper.orderByDesc(DEFAULT_ORDER_BY_FIELD);
        }
        return wrapper.lambda();
    }

    /**
     * 通过主键批量删除
     *
     * @param primaryKeys 主键列表
     */
    public void removeBatchByPrimaryKey(Collection<PrimaryKey> primaryKeys) {
        if (CollUtil.isNotEmpty(primaryKeys)) {
            this.mapper.deleteBatchIds(primaryKeys);
        }
    }

    /**
     * 通过业务id列表批量删除
     *
     * @param businessIds 业务id列表
     */
    public void removeBatchByIds(Collection<ID> businessIds, SFunction<Entity, ?> column) {
        if (CollUtil.isNotEmpty(businessIds)) {
            LambdaUpdateWrapper<Entity> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.in(column, businessIds);
            this.mapper.delete(updateWrapper);
        }
    }

    /**
     * 通过业务id列表批量删除
     *
     * @param businessIds 业务id列表
     */
    public abstract void removeBatchByIds(Collection<ID> businessIds);

    /**
     * 创建实体对应的BO对象
     *
     * @param entities 实体列表
     * @return BO对象列表
     */
    public List<EntityBo> createBo(List<Entity> entities) {
        if (CollUtil.isEmpty(entities)) {
            return Collections.emptyList();
        }

        List<EntityBo> entityBos = new ArrayList<>();
        for (Entity entity : entities) {
            EntityBo entityBo = BeanUtil.copyProperties(entity, entityBoClass);
            if (Objects.nonNull(entityBo)) {
                entityBos.add(entityBo);
            }
        }
        return entityBos;
    }
}
